use core::fmt::{self, Write};

use crate::serial::Serial;

cfg_if::cfg_if! {
    if #[cfg(feature = "print_pl011")] {
        use crate::serial::pl011::Pl011State;

        static mut PRINT_OUTPUT: Option<Serial<Pl011State>> = None;

        pub fn setup_print(s: Serial<Pl011State>) {
            unsafe {
                PRINT_OUTPUT = Some(s);
            }
        }
    } else {
        use crate::serial::SerialWrite;

        pub struct PrintEmpty;

        impl SerialWrite for PrintEmpty {
            fn init(&mut self, _: usize, _: u32, _: u32) -> Result<(), ()> {
                Err(())
            }

            fn write(&mut self, _: &[u8]) -> Result<(), ()> {
                Err(())
            }
        }

        static mut PRINT_OUTPUT: Option<Serial<PrintEmpty>> = None;

        pub fn setup_print(s: Serial<PrintEmpty>) {
            unsafe {
                PRINT_OUTPUT = Some(s);
            }
        }
    }
}

pub fn _print(args: fmt::Arguments<'_>) {
    unsafe {
        if let Some(o) = &mut PRINT_OUTPUT {
            o.write_fmt(args).unwrap();
        }
    }
}

#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => {{
        $crate::print::_print(core::format_args!($($arg)*));
    }};
}

#[macro_export]
macro_rules! println {
    () => {
        $crate::print!("\n")
    };
    ($($arg:tt)*) => {{
        $crate::print::_print(core::format_args_nl!($($arg)*));
    }};
}
